home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / bind-contrib.tar.gz / bind-contrib.tar / contrib / arlib / arlib.c < prev    next >
C/C++ Source or Header  |  1996-10-25  |  20KB  |  921 lines

  1. /*
  2.  * arlib.c (C)opyright 1993 Darren Reed. All rights reserved.
  3.  * This file may not be distributed without the author's permission in any
  4.  * shape or form. The author takes no responsibility for any damage or loss
  5.  * of property which results from the use of this software.
  6.  */
  7. #ifndef lint
  8. static    char    sccsid[] = "@(#)arlib.c    1.9 6/5/93 (C)opyright 1992 Darren \
  9. Reed. ASYNC DNS";
  10. #endif
  11.  
  12. #include <stdio.h>
  13. #include <fcntl.h>
  14. #include <signal.h>
  15. #include <sys/types.h>
  16. #include <sys/time.h>
  17. #include <sys/socket.h>
  18. #include <netinet/in.h>
  19. #include "netdb.h"
  20. #include "sys/bitypes.h"
  21. #include "arpa/nameser.h"
  22. #include <resolv.h>
  23. #include "arlib.h"
  24.  
  25. extern    int    errno, h_errno;
  26. static    char    ar_hostbuf[65], ar_domainname[65];
  27. static    char    ar_dot[] = ".";
  28. static    int    ar_resfd = -1, ar_vc = 0;
  29. static    struct    reslist    *ar_last, *ar_first;
  30. static    int    do_query_name(), do_query_number(), ar_resend_query();
  31.  
  32. /*
  33.  * Statistics structure.
  34.  */
  35. static    struct    resstats {
  36.     int    re_errors;
  37.     int    re_nu_look;
  38.     int    re_na_look;
  39.     int    re_replies;
  40.     int    re_requests;
  41.     int    re_resends;
  42.     int    re_sent;
  43.     int    re_timeouts;
  44. } ar_reinfo;
  45.  
  46. /*
  47.  * ar_init
  48.  *
  49.  * Initializes the various ARLIB internal varilables and related DNS
  50.  * options for res_init().
  51.  *
  52.  * Returns 0 or the socket opened for use with talking to name servers
  53.  * if 0 is passed or ARES_INITSOCK is set.
  54.  */
  55. int    ar_init(op)
  56. int    op;
  57. {
  58.     int    ret = 0;
  59.  
  60.     if (op & ARES_INITLIST)
  61.         {
  62.         bzero(&ar_reinfo, sizeof(ar_reinfo));
  63.         ar_first = ar_last = NULL;
  64.         }
  65.  
  66.     if (op & ARES_CALLINIT && !(_res.options & RES_INIT))
  67.         {
  68.         ret = res_init();
  69.         (void)strcpy(ar_domainname, ar_dot);
  70.         (void)strncat(ar_domainname, _res.defdname,
  71.                 sizeof(ar_domainname)-2);
  72.         }
  73.  
  74.     if (op & ARES_INITSOCK)
  75.         ret = ar_resfd = ar_open();
  76.  
  77.     if (op & ARES_INITDEBG)
  78.         _res.options |= RES_DEBUG;
  79.  
  80.     if (op == 0)
  81.         ret = ar_resfd;
  82.  
  83.     return ret;
  84. }
  85.  
  86. /*
  87.  * ar_open
  88.  *
  89.  * Open a socket to talk to a name server with.
  90.  * Check _res.options to see if we use a TCP or UDP socket.
  91.  */
  92. int    ar_open()
  93. {
  94.     if (ar_resfd == -1)
  95.         {
  96.         if (_res.options & RES_USEVC)
  97.             {
  98.             struct    sockaddr_in *sip;
  99.             int    i;
  100.  
  101.             sip = _res.nsaddr_list;
  102.             ar_vc = 1;
  103.             ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
  104.  
  105.             /*
  106.              * Try each name server listed in sequence until we
  107.              * succeed or run out.
  108.              */
  109.             while (connect(ar_resfd, (struct sockaddr *)sip++,
  110.                     sizeof(struct sockaddr)))
  111.                 {
  112.                 (void)close(ar_resfd);
  113.                 ar_resfd = -1;
  114.                 if (i >= _res.nscount)
  115.                     break;
  116.                 ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
  117.                 }
  118.             }
  119.         else
  120.             ar_resfd = socket(AF_INET, SOCK_DGRAM, 0);
  121.         }
  122.     if (ar_resfd >= 0)
  123.         {    /* Need one of these two here - and it MUST work!! */
  124.         int flags;
  125.  
  126.         if ((flags = fcntl(ar_resfd, F_GETFL, 0)) != -1)
  127. #ifdef    O_NONBLOCK
  128.              if (fcntl(ar_resfd, F_SETFL, flags|O_NONBLOCK) == -1)
  129. #else
  130. # ifdef    O_NDELAY
  131.              if (fcntl(ar_resfd, F_SETFL, flags|O_NDELAY) == -1)
  132. # else
  133. #  ifdef    FNDELAY
  134.              if (fcntl(ar_resfd, F_SETFL, flags|FNDELAY) == -1)
  135. #  endif
  136. # endif
  137. #endif
  138.             {
  139.             (void)close(ar_resfd);
  140.             ar_resfd = -1;
  141.             }
  142.         }
  143.     return ar_resfd;
  144. }
  145.  
  146. /*
  147.  * ar_close
  148.  *
  149.  * Closes and flags the ARLIB socket as closed.
  150.  */
  151. void    ar_close()
  152. {
  153.     (void)close(ar_resfd);
  154.     ar_resfd = -1;
  155.     return;
  156. }
  157.  
  158. /*
  159.  * ar_add_request
  160.  *
  161.  * Add a new DNS query to the end of the query list.
  162.  */
  163. static    int    ar_add_request(new)
  164. struct    reslist *new;
  165. {
  166.     if (!new)
  167.         return -1;
  168.     if (!ar_first)
  169.         ar_first = ar_last = new;
  170.     else {
  171.         ar_last->re_next = new;
  172.         ar_last = new;
  173.     }
  174.     new->re_next = NULL;
  175.     ar_reinfo.re_requests++;
  176.     return 0;
  177. }
  178.  
  179. /*
  180.  * ar_remrequest
  181.  *
  182.  * Remove a request from the list. This must also free any memory that has
  183.  * been allocated for temporary storage of DNS results.
  184.  *
  185.  * Returns -1 if there are anyy problems removing the requested structure
  186.  * or 0 if the remove is successful.
  187.  */
  188. static    int    ar_remrequest(old)
  189. struct    reslist *old;
  190. {
  191.     register struct    reslist    *rptr, *r2ptr;
  192.     register char    **s;
  193.  
  194.     if (!old)
  195.         return -1;
  196.     for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next)
  197.         {
  198.         if (rptr == old)
  199.             break;
  200.         r2ptr = rptr;
  201.         }
  202.  
  203.     if (!rptr)
  204.         return -1;
  205.     if (rptr == ar_first)
  206.         ar_first = ar_first->re_next;
  207.     else if (rptr == ar_last)
  208.         {
  209.         if (ar_last = r2ptr)
  210.             ar_last->re_next = NULL;
  211.         }
  212.     else
  213.         r2ptr->re_next = rptr->re_next;
  214.  
  215.     if (!ar_first)
  216.         ar_last = ar_first;
  217.     if (rptr->re_he.h_name)
  218.         (void)free(rptr->re_he.h_name);
  219.     if (s = rptr->re_he.h_aliases)
  220.         for (; *s; s++)
  221.             (void)free(*s);
  222.     if (rptr->re_rinfo.ri_ptr)
  223.         (void)free(rptr->re_rinfo.ri_ptr);
  224.     (void)free(rptr);
  225.  
  226.     return 0;
  227. }
  228.  
  229. /*
  230.  * ar_make_request
  231.  *
  232.  * Create a DNS query recorded for the request being made and place it on the
  233.  * current list awaiting replies.  Initialization of the record with set
  234.  * values should also be done.
  235.  */
  236. static    struct    reslist    *ar_make_request(resi)
  237. register struct    resinfo    *resi;
  238. {
  239.     register struct    reslist    *rptr;
  240.     register struct resinfo *rp;
  241.  
  242.     rptr = (struct reslist *)calloc(1, sizeof(struct reslist));
  243.     rp = &rptr->re_rinfo;
  244.  
  245.     rptr->re_next    = NULL; /* where NULL is non-zero ;) */
  246.     rptr->re_sentat  = time(NULL);
  247.     rptr->re_retries = _res.retry;
  248.     rptr->re_sends = 1;
  249.     rptr->re_resend  = 1;
  250.     rptr->re_timeout = rptr->re_sentat + _res.retrans;
  251.     rptr->re_he.h_name = NULL;
  252.     rptr->re_he.h_addrtype   = AF_INET;
  253.     rptr->re_he.h_aliases[0] = NULL;
  254.     rp->ri_ptr = resi->ri_ptr;
  255.     rp->ri_size = resi->ri_size;
  256.  
  257.     (void)ar_add_request(rptr);
  258.  
  259.     return rptr;
  260. }
  261.  
  262. /*
  263.  * ar_timeout
  264.  *
  265.  * Remove queries from the list which have been there too long without
  266.  * being resolved.
  267.  */
  268. long    ar_timeout(now, info, size)
  269. long    now;
  270. char    *info;
  271. int    size;
  272. {
  273.     register struct    reslist    *rptr, *r2ptr;
  274.     register long    next = 0;
  275.  
  276.     for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr)
  277.         {
  278.         r2ptr = rptr->re_next;
  279.         if (now >= rptr->re_timeout)
  280.             {
  281.             /*
  282.              * If the timeout for the query has been exceeded,
  283.              * then resend the query if we still have some
  284.              * 'retry credit' and reset the timeout. If we have
  285.              * used it all up, then remove the request.
  286.              */
  287.             if (--rptr->re_retries <= 0)
  288.                 {
  289.                 ar_reinfo.re_timeouts++;
  290.                 if (info && rptr->re_rinfo.ri_ptr)
  291.                     bcopy(rptr->re_rinfo.ri_ptr, info,
  292.                         MIN(rptr->re_rinfo.ri_size, size));
  293.                 (void)ar_remrequest(rptr);
  294.                 return now;
  295.                 }
  296.             else
  297.                 {
  298.                 rptr->re_sends++;
  299.                 rptr->re_sentat = now;
  300.                 rptr->re_timeout = now + _res.retrans;
  301.                 (void)ar_resend_query(rptr);
  302.                 }
  303.             }
  304.         if (!next || rptr->re_timeout < next)
  305.             next = rptr->re_timeout;
  306.         }
  307.     return next;
  308. }
  309.  
  310. /*
  311.  * ar_send_res_msg
  312.  *
  313.  * When sending queries to nameservers listed in the resolv.conf file,
  314.  * don't send a query to every one, but increase the number sent linearly
  315.  * to match the number of resends. This increase only occurs if there are
  316.  * multiple nameserver entries in the resolv.conf file.
  317.  * The return value is the number of messages successfully sent to 
  318.  * nameservers or -1 if no successful sends.
  319.  */
  320. static    int    ar_send_res_msg(msg, len, rcount)
  321. char    *msg;
  322. int    len, rcount;
  323. {
  324.     register int    i;
  325.     int    sent = 0;
  326.  
  327.     if (!msg)
  328.         return -1;
  329.  
  330.     rcount = (_res.nscount > rcount) ? rcount : _res.nscount;
  331.     if (_res.options & RES_PRIMARY)
  332.         rcount = 1;
  333.  
  334.     if (ar_vc)
  335.         {
  336.         ar_reinfo.re_sent++;
  337.         sent++;
  338.         if (write(ar_resfd, msg, len) == -1)
  339.             {
  340.             int errtmp = errno;
  341.             (void)close(ar_resfd);
  342.             errno = errtmp;
  343.             ar_resfd = -1;
  344.             }
  345.         }
  346.     else
  347.         for (i = 0; i < rcount; i++)
  348.             {
  349.             if (sendto(ar_resfd, msg, len, 0,
  350.                    (struct sockaddr *)&(_res.nsaddr_list[i]),
  351.                 sizeof(struct sockaddr_in)) == len)
  352.                 {
  353.                 ar_reinfo.re_sent++;
  354.                 sent++;
  355.                 }
  356.             }
  357.     return (sent) ? sent : -1;
  358. }
  359.  
  360. /*
  361.  * ar_find_id
  362.  *
  363.  * find a dns query record by the id (id is determined by dn_mkquery)
  364.  */
  365. static    struct    reslist    *ar_find_id(id)
  366. int    id;
  367. {
  368.     register struct    reslist    *rptr;
  369.  
  370.     for (rptr = ar_first; rptr; rptr = rptr->re_next)
  371.         if (rptr->re_id == id)
  372.             return rptr;
  373.     return NULL;
  374. }
  375.  
  376. /*
  377.  * ar_delete
  378.  *
  379.  * Delete a request from the waiting list if it has a data pointer which
  380.  * matches the one passed.
  381.  */
  382. int    ar_delete(ptr, size)
  383. char    *ptr;
  384. int    size;
  385. {
  386.     register struct    reslist    *rptr;
  387.     register struct    reslist    *r2ptr;
  388.     int    removed = 0;
  389.  
  390.     for (rptr = ar_first; rptr; rptr = r2ptr)
  391.         {
  392.         r2ptr = rptr->re_next;
  393.         if (rptr->re_rinfo.ri_ptr && ptr && size &&
  394.             bcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0)
  395.             {
  396.             (void)ar_remrequest(rptr);
  397.             removed++;
  398.             }
  399.         }
  400.     return removed;
  401. }
  402.  
  403. /*
  404.  * ar_query_name
  405.  *
  406.  * generate a query based on class, type and name.
  407.  */
  408. static    int    ar_query_name(name, class, type, rptr)
  409. char    *name;
  410. int    class, type;
  411. struct    reslist    *rptr;
  412. {
  413.     static    char buf[MAXPACKET];
  414.     int    r,s,a;
  415.     HEADER    *hptr;
  416.  
  417.     bzero(buf, sizeof(buf));
  418.     r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
  419.             buf, sizeof(buf));
  420.     if (r <= 0)
  421.         {
  422.         h_errno = NO_RECOVERY;
  423.         return r;
  424.         }
  425.     hptr = (HEADER *)buf;
  426.     rptr->re_id = ntohs(hptr->id);
  427.  
  428.     s = ar_send_res_msg(buf, r, rptr->re_sends);
  429.  
  430.     if (s == -1)
  431.         {
  432.         h_errno = TRY_AGAIN;
  433.         return -1;
  434.         }
  435.     else
  436.         rptr->re_sent += s;
  437.     return 0;
  438. }
  439.  
  440. /*
  441.  * ar_gethostbyname
  442.  *
  443.  * Replacement library function call to gethostbyname().  This one, however,
  444.  * doesn't return the record being looked up but just places the query in the
  445.  * queue to await answers.
  446.  */
  447. int    ar_gethostbyname(name, info, size)
  448. char    *name;
  449. char    *info;
  450. int    size;
  451. {
  452.     char    host[65];
  453.     struct    resinfo    resi;
  454.     register struct resinfo *rp = &resi;
  455.  
  456.     if (size && info)
  457.         {
  458.         rp->ri_ptr = (char *)malloc(size);
  459.         bcopy(info, rp->ri_ptr, size);
  460.         rp->ri_size = size;
  461.         }
  462.     else
  463.         bzero((char *)rp, sizeof(resi));
  464.     ar_reinfo.re_na_look++;
  465.     (void)strncpy(host, name, 64);
  466.     host[64] = '\0';
  467.  
  468.     return (do_query_name(rp, host, NULL));
  469. }
  470.  
  471. static    int    do_query_name(resi, name, rptr)
  472. struct    resinfo    *resi;
  473. char    *name;
  474. register struct    reslist    *rptr;
  475. {
  476.     char    hname[65];
  477.     int    len;
  478.  
  479.     len = strlen((char *)strncpy(hname, name, sizeof(hname)-1));
  480.  
  481.     if (rptr && (hname[len-1] != '.'))
  482.         {
  483.         (void)strncat(hname, ar_dot, sizeof(hname)-len-1);
  484.         /*
  485.          * NOTE: The logical relationship between DNSRCH and DEFNAMES
  486.          * is implies. ie no DEFNAES, no DNSRCH.
  487.          */
  488.         if (_res.options & (RES_DEFNAMES|RES_DNSRCH) ==
  489.             (RES_DEFNAMES|RES_DNSRCH))
  490.             {
  491.             if (_res.dnsrch[rptr->re_srch])
  492.                 (void)strncat(hname, _res.dnsrch[rptr->re_srch],
  493.                     sizeof(hname) - ++len -1);
  494.             }
  495.         else if (_res.options & RES_DEFNAMES)
  496.             (void)strncat(hname, ar_domainname, sizeof(hname) - len -1);
  497.         }
  498.  
  499.     /*
  500.      * Store the name passed as the one to lookup and generate other host
  501.      * names to pass onto the nameserver(s) for lookups.
  502.      */
  503.     if (!rptr)
  504.         {
  505.         rptr = ar_make_request(resi);
  506.         rptr->re_type = T_A;
  507.         (void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1);
  508.         }
  509.     return (ar_query_name(hname, C_IN, T_A, rptr));
  510. }
  511.  
  512. /*
  513.  * ar_gethostbyaddr
  514.  *
  515.  * Generates a query for a given IP address.
  516.  */
  517. int    ar_gethostbyaddr(addr, info, size)
  518. char    *addr;
  519. char    *info;
  520. int    size;
  521. {
  522.     struct    resinfo    resi;
  523.     register struct resinfo *rp = &resi;
  524.  
  525.     if (size && info)
  526.         {
  527.         rp->ri_ptr = (char *)malloc(size);
  528.         bcopy(info, rp->ri_ptr, size);
  529.         rp->ri_size = size;
  530.         }
  531.     else
  532.         bzero((char *)rp, sizeof(resi));
  533.     ar_reinfo.re_nu_look++;
  534.     return (do_query_number(rp, addr, NULL));
  535. }
  536.  
  537. /*
  538.  * do_query_number
  539.  *
  540.  * Use this to do reverse IP# lookups.
  541.  */
  542. static    int    do_query_number(resi, numb, rptr)
  543. struct    resinfo    *resi;
  544. char    *numb;
  545. register struct    reslist    *rptr;
  546. {
  547.     register unsigned char    *cp;
  548.     static    char    ipbuf[32];
  549.  
  550.     /*
  551.      * Generate name in the "in-addr.arpa" domain.  No addings bits to this
  552.      * name to get more names to query!.
  553.      */
  554.     cp = (unsigned char *)numb;
  555.     (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.",
  556.             (unsigned int)(cp[3]), (unsigned int)(cp[2]),
  557.             (unsigned int)(cp[1]), (unsigned int)(cp[0]));
  558.  
  559.     if (!rptr)
  560.         {
  561.         rptr = ar_make_request(resi);
  562.         rptr->re_type = T_PTR;
  563.         rptr->re_he.h_length = sizeof(struct in_addr);
  564.         bcopy(numb, (char *)&rptr->re_addr, rptr->re_he.h_length);
  565.         bcopy(numb, (char *)&rptr->re_he.h_addr_list[0].s_addr,
  566.             rptr->re_he.h_length);
  567.         }
  568.     return (ar_query_name(ipbuf, C_IN, T_PTR, rptr));
  569. }
  570.  
  571. /*
  572.  * ar_resent_query
  573.  *
  574.  * resends a query.
  575.  */
  576. static    int    ar_resend_query(rptr)
  577. struct    reslist    *rptr;
  578. {
  579.     if (!rptr->re_resend)
  580.         return -1;
  581.  
  582.     switch(rptr->re_type)
  583.     {
  584.     case T_PTR:
  585.         ar_reinfo.re_resends++;
  586.         return do_query_number(NULL, rptr->re_addr, rptr);
  587.     case T_A:
  588.         ar_reinfo.re_resends++;
  589.         return do_query_name(NULL, rptr->re_name, rptr);
  590.     default:
  591.         break;
  592.     }
  593.  
  594.     return -1;
  595. }
  596.  
  597. /*
  598.  * ar_procanswer
  599.  *
  600.  * process an answer received from a nameserver.
  601.  */
  602. static    int    ar_procanswer(rptr, hptr, buf, eob)
  603. struct    reslist    *rptr;
  604. char    *buf, *eob;
  605. HEADER    *hptr;
  606. {
  607.     char    *cp, **alias, *s;
  608.     int    class, type, dlen, len, ans = 0, n, i;
  609.     u_int32_t ttl, dr, *adr;
  610.     struct    hent    *hp;
  611.  
  612.     cp = buf + HFIXEDSZ;
  613.     adr = (u_int32_t *)rptr->re_he.h_addr_list;
  614.  
  615.     while (*adr)
  616.         adr++;
  617.  
  618.     alias = rptr->re_he.h_aliases;
  619.     while (*alias)
  620.         alias++;
  621.  
  622.     hp = &rptr->re_he;
  623.  
  624.  
  625.     /*
  626.      * Skip over the original question.
  627.      */
  628.     while (hptr->qdcount-- > 0)
  629.         cp += dn_skipname(cp, eob) + QFIXEDSZ;
  630.     /*
  631.      * proccess each answer sent to us. blech.
  632.      */
  633.     while (hptr->ancount-- > 0 && cp < eob) {
  634.         n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf));
  635.         cp += n;
  636.         if (n <= 0)
  637.             return ans;
  638.  
  639.         ans++;
  640.         /*
  641.          * 'skip' past the general dns crap (ttl, class, etc) to get
  642.          * the pointer to the right spot.  Some of thse are actually
  643.          * useful so its not a good idea to skip past in one big jump.
  644.          */
  645.         type = (int)_getshort(cp);
  646.         cp += sizeof(short);
  647.         class = (int)_getshort(cp);
  648.         cp += sizeof(short);
  649.         ttl = (u_int32_t)_getlong(cp);
  650.         cp += INT32SZ;
  651.         dlen =  (int)_getshort(cp);
  652.         cp += sizeof(short);
  653.         rptr->re_type = type;
  654.  
  655.         switch(type)
  656.         {
  657.         case T_A :
  658.             rptr->re_he.h_length = dlen;
  659.             if (ans == 1)
  660.                 rptr->re_he.h_addrtype=(class == C_IN) ?
  661.                             AF_INET : AF_UNSPEC;
  662.             bcopy(cp, &dr, dlen);
  663.             *adr++ = dr;
  664.             *adr = 0;
  665.             cp += dlen;
  666.             len = strlen(ar_hostbuf);
  667.             if (!rptr->re_he.h_name)
  668.                 {
  669.                 rptr->re_he.h_name = (char *)malloc(len+1);
  670.                 (void)strcpy(rptr->re_he.h_name, ar_hostbuf);
  671.                 }
  672.              break;
  673.         case T_PTR :
  674.             if ((n = dn_expand(buf, eob, cp, ar_hostbuf,
  675.                        sizeof(ar_hostbuf) )) < 0)
  676.                 {
  677.                 cp += n;
  678.                 continue;
  679.                 }
  680.             cp += n;
  681.             len = strlen(ar_hostbuf)+1;
  682.             /*
  683.              * copy the returned hostname into the host name
  684.              * or alias field if there is a known hostname
  685.              * already.
  686.              */
  687.             if (!rptr->re_he.h_name)
  688.                 {
  689.                 rptr->re_he.h_name = (char *)malloc(len);
  690.                 (void)strcpy(rptr->re_he.h_name, ar_hostbuf);
  691.                 }
  692.             else
  693.                 {
  694.                 *alias = (char *)malloc(len);
  695.                 if (!*alias)
  696.                     return -1;
  697.                 (void)strcpy(*alias++, ar_hostbuf);
  698.                 *alias = NULL;
  699.                 }
  700.             break;
  701.         case T_CNAME :
  702.             cp += dlen;
  703.             if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1]))
  704.                 continue;
  705.             n = strlen(ar_hostbuf)+1;
  706.             *alias = (char *)malloc(n);
  707.             if (!*alias)
  708.                 return -1;
  709.             (void)strcpy(*alias++, ar_hostbuf);
  710.             *alias = NULL;
  711.             break;
  712.         default :
  713.             break;
  714.         }
  715.     }
  716.  
  717.     return ans;
  718. }
  719.  
  720. /*
  721.  * ar_answer
  722.  *
  723.  * Get an answer from a DNS server and process it.  If a query is found to
  724.  * which no answer has been given to yet, copy its 'info' structure back
  725.  * to where "reip" points and return a pointer to the hostent structure.
  726.  */
  727. struct    hostent    *ar_answer(reip, size)
  728. char    *reip;
  729. int    size;
  730. {
  731.     static    char    ar_rcvbuf[HFIXEDSZ + MAXPACKET];
  732.     static    struct    hostent    ar_host;
  733.  
  734.     register HEADER    *hptr;
  735.     register struct    reslist    *rptr = NULL;
  736.     register struct hostent *hp;
  737.     register char **s;
  738.     unsigned long    *adr;
  739.     int    rc, i, n, a;
  740.  
  741.     rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0);
  742.     if (rc <= 0)
  743.         goto getres_err;
  744.  
  745.     ar_reinfo.re_replies++;
  746.     hptr = (HEADER *)ar_rcvbuf;
  747.     /*
  748.      * convert things to be in the right order.
  749.      */
  750.     hptr->id = ntohs(hptr->id);
  751.     hptr->ancount = ntohs(hptr->ancount);
  752.     hptr->arcount = ntohs(hptr->arcount);
  753.     hptr->nscount = ntohs(hptr->nscount);
  754.     hptr->qdcount = ntohs(hptr->qdcount);
  755.     /*
  756.      * response for an id which we have already received an answer for
  757.      * just ignore this response.
  758.      */
  759.     rptr = ar_find_id(hptr->id);
  760.     if (!rptr)
  761.         goto getres_err;
  762.  
  763.     if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
  764.         {
  765.         switch (hptr->rcode)
  766.         {
  767.         case NXDOMAIN:
  768.             h_errno = HOST_NOT_FOUND;
  769.             break;
  770.         case SERVFAIL:
  771.             h_errno = TRY_AGAIN;
  772.             break;
  773.         case NOERROR:
  774.             h_errno = NO_DATA;
  775.             break;
  776.         case FORMERR:
  777.         case NOTIMP:
  778.         case REFUSED:
  779.         default:
  780.             h_errno = NO_RECOVERY;
  781.             break;
  782.         }
  783.         ar_reinfo.re_errors++;
  784.         /*
  785.         ** If a bad error was returned, we stop here and dont send
  786.         ** send any more (no retries granted).
  787.         */
  788.         if (h_errno != TRY_AGAIN)
  789.             {
  790.             rptr->re_resend = 0;
  791.             rptr->re_retries = 0;
  792.             }
  793.         goto getres_err;
  794.         }
  795.  
  796.     a = ar_procanswer(rptr, hptr, ar_rcvbuf, ar_rcvbuf+rc);
  797.  
  798.     if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR))
  799.         {
  800.         /*
  801.          * For reverse lookups on IP#'s, lookup the name that is given
  802.          * for the ip# and return with that as the official result.
  803.          * -avalon
  804.          */
  805.         rptr->re_type = T_A;
  806.         /*
  807.          * Clean out the list of addresses already set, even though
  808.          * there should only be one :)
  809.          */
  810.         adr = (unsigned long *)rptr->re_he.h_addr_list;
  811.         while (*adr)
  812.             *adr++ = 0L;
  813.         /*
  814.          * Lookup the name that we were given for the ip#
  815.          */
  816.         ar_reinfo.re_na_look++;
  817.         (void)strncpy(rptr->re_name, rptr->re_he.h_name,
  818.             sizeof(rptr->re_name)-1);
  819.         rptr->re_he.h_name = NULL;
  820.         rptr->re_retries = _res.retry;
  821.         rptr->re_sends = 1;
  822.         rptr->re_resend = 1;
  823.         rptr->re_he.h_name = NULL;
  824.         ar_reinfo.re_na_look++;
  825.         (void)ar_query_name(rptr->re_name, C_IN, T_A, rptr);
  826.         return NULL;
  827.         }
  828.  
  829.     if (reip && rptr->re_rinfo.ri_ptr && size)
  830.         bcopy(rptr->re_rinfo.ri_ptr, reip,
  831.             MIN(rptr->re_rinfo.ri_size, size));
  832.     /*
  833.      * Clean up structure from previous usage.
  834.      */
  835.     hp = &ar_host;
  836.     if (hp->h_name)
  837.         (void)free(hp->h_name);
  838.     if (s = hp->h_aliases)
  839.         {
  840.         while (*s)
  841.             (void)free(*s++);
  842.         (void)free(hp->h_aliases);
  843.         }
  844.     if (s = hp->h_addr_list)
  845.         {
  846.         while (*s)
  847.             (void)free(*s++);
  848.         (void)free(hp->h_addr_list);
  849.         }
  850.     bzero((char *)hp, sizeof(*hp));
  851.     /*
  852.      * Setup and copy details for the structure we return a pointer to.
  853.      */
  854.     hp->h_addrtype = AF_INET;
  855.     hp->h_length = sizeof(struct in_addr);
  856.     hp->h_name = (char *)malloc(strlen(rptr->re_he.h_name)+1);
  857.     (void)strcpy(hp->h_name, rptr->re_he.h_name);
  858.     /*
  859.      * Count IP#'s.
  860.      */
  861.     for (i = 0, n = 0; i < MAXADDRS; i++, n++)
  862.         if (!rptr->re_he.h_addr_list[i].s_addr)
  863.             break;
  864.     s = hp->h_addr_list = (char **)malloc((n + 1) * sizeof(char *));
  865.     if (n)
  866.         {
  867.         *s = (char *)malloc(n * sizeof(struct in_addr));
  868.         bcopy((char *)&rptr->re_he.h_addr_list[0].s_addr, *s,
  869.             sizeof(struct in_addr));
  870.         s++;
  871.         for (i = 1; i < n; i++, s++)
  872.             {
  873.             *s = hp->h_addr + i * sizeof(struct in_addr);
  874.             bcopy((char *)&rptr->re_he.h_addr_list[i].s_addr, *s,
  875.                 sizeof(struct in_addr));
  876.             }
  877.         }
  878.     *s = NULL;
  879.     /*
  880.      * Count CNAMEs
  881.      */
  882.     for (i = 0, n = 0; i < MAXADDRS; i++, n++)
  883.         if (!rptr->re_he.h_aliases[i])
  884.             break;
  885.     s = hp->h_aliases = (char **)malloc((n + 1) * sizeof(char *));
  886.     for (i = 0; i < n; i++)
  887.         {
  888.         *s++ = rptr->re_he.h_aliases[i];
  889.         rptr->re_he.h_aliases[i] = NULL;
  890.         }
  891.     *s = NULL;
  892.  
  893.     if (a > 0)
  894.         (void)ar_remrequest(rptr);
  895.     else
  896.         if (!rptr->re_sent)
  897.             (void)ar_remrequest(rptr);
  898.     return hp;
  899.  
  900. getres_err:
  901.     if (rptr)
  902.         {
  903.         if (reip && rptr->re_rinfo.ri_ptr && size)
  904.             bcopy(rptr->re_rinfo.ri_ptr, reip,
  905.                 MIN(rptr->re_rinfo.ri_size, size));
  906.         if ((h_errno != TRY_AGAIN) &&
  907.             (_res.options & (RES_DNSRCH|RES_DEFNAMES) ==
  908.              (RES_DNSRCH|RES_DEFNAMES) ))
  909.             if (_res.dnsrch[rptr->re_srch])
  910.                 {
  911.                 rptr->re_retries = _res.retry;
  912.                 rptr->re_sends = 1;
  913.                 rptr->re_resend = 1;
  914.                 (void)ar_resend_query(rptr);
  915.                 rptr->re_srch++;
  916.                 }
  917.         return NULL;
  918.         }
  919.     return NULL;
  920. }
  921.